from PySide6 import QtWidgets
from PySide6 import QtCore
from PySide6 import QtGui

import requests
import threading
from bs4 import BeautifulSoup


class ReptileInfo:

    def __init__(self, url:str, saved_path:str):
        
        self.url = url
        self.saved_path = saved_path

class DownloadThread(QtCore.QThread):
    finished = QtCore.Signal()

    def __init__(self):
        super().__init__()
        self.reptile_info:ReptileInfo = None
        self.isFinish = False

        # 成功 -> 0 失败 -> 1 取消 -> 2
        self.download_result = 0

    def run(self):
        '''
        开始爬虫
        '''
        self.isFinish = False

        if self.reptile_info == None:
            return
        
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0'
        }

        response = requests.get(self.reptile_info.url, headers=header)
        if response.ok:
            self.download_result = 0
            # 解析 html
            soup = BeautifulSoup(response.text, "html.parser")
            label_imgs = soup.find_all("img")
            for label in label_imgs:

                # 检查是否取消后面的下载
                if self.isFinish:
                    self.download_result = 2
                    break

                img_url = label.attrs.get("src")
                if img_url == None:
                    continue

                file_info = QtCore.QFileInfo(img_url)

                img_name = label.attrs.get("alt")
                if (img_name == "") or (img_name == None):
                    img_name = file_info.baseName()

                img_suffix = file_info.suffix()

                # 开始下载
                with requests.get(img_url, headers=header) as response:
                    if response.ok:
                        try:
                            with open(f"{self.reptile_info.saved_path}/{img_name}.{img_suffix}", "wb") as file:
                                file.write(response.content)
                        except:
                            ...
                    else:
                        ...
                        #print(f"下载失败：{img_url}")
        else:
            self.download_result = 1

        # 完成
        self.finished.emit()

    def stop(self):
        self.isFinish = True

class ReptileDialog(QtWidgets.QDialog):

    OnCancel = QtCore.Signal()
    
    def __init__(self, parent):
        super().__init__(parent)

        self.setWindowTitle("下载提示")
        self.setWindowFlag(QtCore.Qt.WindowType.WindowCloseButtonHint, False)
        self.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
        self.setMinimumSize(200, 100)

        self.vlayout = QtWidgets.QVBoxLayout(self)

        self.label_info = QtWidgets.QLabel("正在下载图片 ...")
        self.vlayout.addWidget(self.label_info)

        self.hbox = QtWidgets.QHBoxLayout()
        self.btn_cancel = QtWidgets.QPushButton("取消下载")
        self.btn_cancel.clicked.connect(self.on_cancel)
        self.hbox.addSpacing(50)
        self.hbox.addWidget(self.btn_cancel)
        self.hbox.addSpacing(50)
        self.vlayout.addLayout(self.hbox)

    def on_cancel(self):
        self.OnCancel.emit()

    

class ReptileView(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.thread_download = DownloadThread()
        self.thread_download.finished.connect(self.on_download_finished)

        self.setWindowTitle("网页图片下载")
        self.setWindowFlag(QtCore.Qt.WindowType.WindowStaysOnTopHint, True)
        self.setMinimumSize(400, 150)

        self.create_widgets()
        self.create_layouts()
        self.create_connections()

    def create_widgets(self):
        self.download_dialog = ReptileDialog(self)
        self.download_dialog.OnCancel.connect(self.on_download_cancel)

        self.line_edt_url = QtWidgets.QLineEdit()
        self.line_edt_url.setPlaceholderText("输入网址")

        self.line_edt_saved_path = QtWidgets.QLineEdit()
        self.line_edt_saved_path.setPlaceholderText("保存路径")

        self.btn_get_saved_path = QtWidgets.QPushButton("选择保存路径")

        self.btn_download = QtWidgets.QPushButton("确认下载")

        self.line_edt_msg = QtWidgets.QLineEdit()
        self.line_edt_msg.setReadOnly(True)
        self.line_edt_msg.setFrame(False)


    def create_layouts(self):
        self.vbox = QtWidgets.QVBoxLayout(self)
        self.vbox.addWidget(self.line_edt_url)

        self.hbox_saved_path = QtWidgets.QHBoxLayout()
        self.hbox_saved_path.addWidget(self.line_edt_saved_path)
        self.hbox_saved_path.addWidget(self.btn_get_saved_path)
        self.vbox.addLayout(self.hbox_saved_path)

        self.hbox_download = QtWidgets.QHBoxLayout()
        self.hbox_download.addSpacing(150)
        self.hbox_download.addWidget(self.btn_download)
        self.hbox_download.addSpacing(150)
        self.vbox.addLayout(self.hbox_download)

        self.vbox.addWidget(self.line_edt_msg)

    def create_connections(self):
        self.btn_get_saved_path.clicked.connect(self.on_get_saved_path)
        self.btn_download.clicked.connect(self.on_download)

    ''' signal funcs'''
    def on_get_saved_path(self):
        '''
        获取网页图片保存路径
        '''
        saved_path = QtWidgets.QFileDialog.getExistingDirectory(self)
        self.line_edt_saved_path.setText(saved_path)

    def on_download(self):
        '''
        下载图片
        '''
        # 打开提示框
        url = self.line_edt_url.text()
        saved_path = self.line_edt_saved_path.text()
        reptile_info = ReptileInfo(url, saved_path)

        if (reptile_info.url == "") or (reptile_info.saved_path == ""):
            QtWidgets.QMessageBox.warning(self, "警告", "网址或保存路径为空!!!")
            return

        self.thread_download.reptile_info = reptile_info
        self.thread_download.start()

        self.line_edt_msg.setText(f"网页图片：{self.thread_download.reptile_info.url} 开始下载")

        self.download_dialog.show()

    def on_download_finished(self):
        self.download_dialog.close()

        match self.thread_download.download_result:
            case 0:
                # 成功
                self.line_edt_msg.setText(f"网页图片：{self.thread_download.reptile_info.url} 下载完成")
            case 1:
                # 失败
                self.line_edt_msg.setText(f"网页图片：{self.thread_download.reptile_info.url} 不可爬")
            case 2:
                # 取消
                self.line_edt_msg.setText(f"网页图片：{self.thread_download.reptile_info.url} 已取消下载")


        
    def on_download_cancel(self):
        '''
        取消爬虫
        '''
        # 取消线程 并 等待线程完成
        if self.thread_download and self.thread_download.isRunning():
            self.thread_download.stop()
            self.thread_download.wait()
            self.download_dialog.close()






if __name__ == "__main__":
    app = QtWidgets.QApplication()

    reptile_view = ReptileView()
    reptile_view.show()

    app.exec_()